package com.data.hijack.util;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.InetAddress;
import java.net.URL;
import java.net.UnknownHostException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

/**
 *
 * @author husq
 */
public final class StringUtils {
    private static String DELIM_START = "${";
    private static char DELIM_STOP = '}';

    private static int DELIM_START_LEN = 2;

    private static volatile String hostname;

    private static long radix = (long)Math.pow(2, 63) - 1;

    private StringUtils() {
        throw new RuntimeException("not allowed!");
    }

    /**
     * 
     * @return
     */
    public static String getHostName() {
        if (null != hostname && !"".equals(hostname.trim())) {
            return hostname;
        }

        InetAddress addr = null;
        try {
            addr = InetAddress.getLocalHost();
        } catch (UnknownHostException e) {
            e.printStackTrace();
            return "localhost";
        }

        hostname = addr.getCanonicalHostName();

        return hostname;
    }

    public static String getLocalPath() {
        URL url = StringUtils.class.getProtectionDomain().getCodeSource().getLocation();
        String path = url.getPath();

        int endIndex = path.indexOf("classes");
        if (endIndex > 0) {
            path = path.substring(0, endIndex + 7);
        }
        return path;
    }

    public static InputStream getResource(String resourceName) {
        return StringUtils.class.getResourceAsStream(resourceName);
    }

    public static String mergFilePath(String path, String fileName) {
        if (path == null) {
            return fileName == null ? "" : fileName;
        }
        if (fileName == null) {
            return "";
        }

        if (path.endsWith("/") || path.endsWith("\\")) {
            return path + fileName;
        } else {
            return path + "/" + fileName;
        }

    }

    public static String getBase64(String s) {
        if (s == null) {
            return null;
        }
        BASE64Encoder encoder = new BASE64Encoder();
        return encoder.encode(s.getBytes());
    }

    /**
     * 
     * @param bt
     * @return
     */
    public static String getBase64(byte[] bt) {
        if (bt == null) {
            return null;
        }
        BASE64Encoder encoder = new BASE64Encoder();
        return encoder.encode(bt);
    }

    public static String encodeXml(String requestStr) {
        if (requestStr != null) {
            requestStr = requestStr.replace("<", "&lt;");
            requestStr = requestStr.replace(">", "&gt;");
            requestStr = requestStr.replace("&", "&amp;");
            requestStr = requestStr.replace("'", "&apos;");
            requestStr = requestStr.replace("\"", "&quot;");
        }
        return requestStr;
    }

    public static String encode2Base64(String s) {
        String base64Str = getBase64(s);
        if (base64Str != null) {
            return base64Str;
        }
        return "";
    }

    public static String getSrcFromBase64(String s) {
        String charset = System.getProperty("file.encoding");
        return getSrcFromBase64(s, charset);
    }

    /**
     *
     * @param s
     * @param charset
     * @return
     */
    public static String getSrcFromBase64(String s, String charset) {
        if (isBlank(charset)) {
            charset = "GBK";
        }
        if (s == null) {
            return null;
        }
        BASE64Decoder decoder = new BASE64Decoder();
        try {
            return new String(decoder.decodeBuffer(s), charset);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 
     * @param s
     * @return
     * @throws IOException
     */
    public static byte[] decodeBase64(String s) throws IOException {
        if (s == null) {
            return null;
        }
        BASE64Decoder decoder = new BASE64Decoder();
        try {
            return decoder.decodeBuffer(s);
        } catch (IOException e) {
            throw e;
        }
    }

    public static String formatNumber(String number, String format) {
        String strRtn = "";
        if ((number == null) || (number.equals(""))) {
            return "";
        }

        DecimalFormat objFormat = new DecimalFormat();
        objFormat.applyPattern(format);
        double d = Double.parseDouble(number);
        strRtn = objFormat.format(d);

        return strRtn;
    }

    public static String formatDecimal(double decimal, String format) {
        return formatDecimal(new BigDecimal(decimal), format);
    }

    public static String formatDecimal(BigDecimal decimal, String format) {
        if (decimal == null) {
            return "";
        }
        DecimalFormat objFormat = new DecimalFormat(format);

        return objFormat.format(decimal.setScale(2, 4));
    }

    public static String formatDecimal(String number, String format) {
        if ((number == null) || (number.length() == 0)) {
            return "";
        }
        return formatDecimal(new BigDecimal(number), format);
    }

    public static String getEnterSymbol() {
        return "\r";
    }

    public static String getEol() {
        return "\n";
    }

    public static String getEnterAndEol() {
        return "\r\n";
    }

    public static String xmlContentEncode(String text) {
        if ((text == null) || (text.trim().length() == 0)) {
            return text;
        }
        int n = text.length();
        StringBuilder sb = new StringBuilder(n + 20);
        for (int i = 0; i < n; i++) {
            char c = text.charAt(i);
            switch (c) {
                case '<':
                    sb.append("&lt;");
                    break;
                case '>':
                    sb.append("&gt;");
                    break;
                case '&':
                    sb.append("&amp;");
                    break;
                default:
                    sb.append(c);
            }
        }

        return sb.toString();
    }

    public static String xmlContentDecode(String text) {
        if ((text == null) || (text.trim().length() == 0)) {
            return text;
        }
        text = replace(text, "&lt;", "<");
        text = replace(text, "&gt;", ">");
        text = replace(text, "&amp;", "&");

        return text;
    }

    public static String fmtAmt(BigDecimal amt) {
        if (amt == null) {
            return "0.00";
        }

        return amt.toString();
    }

    /**
     *
     * @param str
     * @param src
     * @param dest
     * @return
     */
    public static String replace(String str, String src, String dest) {
        if (str == null || src == null || dest == null) {
            return str;
        }

        int index = str.indexOf(src);
        if (index == -1) {
            return str;
        }

        int oldLen = src.length();
        int replaceLen = dest.length();
        int capacity = str.length();
        if (replaceLen > oldLen) {
            capacity += 16;
        }

        StringBuilder sb = new StringBuilder(capacity);

        int pos = 0;
        while (index >= 0) {
            sb.append(str.substring(pos, index));
            sb.append(dest);
            pos = index + oldLen;
            index = str.indexOf(src, pos);
        }
        sb.append(str.substring(pos));

        return sb.toString();
    }

    /**
     *
     * @param str
     * @param src
     * @param dest
     * @return
     */
    public static String replace2(String str, String src, String dest) {
        int index = str.indexOf(str);
        if (index < 0) {
            return str;
        }

        int flen = src.length();
        StringBuffer sb = new StringBuffer(str.length() + flen);
        while (index >= 0) {
            sb.append(str.substring(0, index));
            sb.append(dest);
            str = str.substring(index + flen);
            index = str.indexOf(src);
        }
        sb.append(str);

        return sb.toString();
    }

    public static String removeChars(String source, char... oldChars) {
        if ((source == null) || (source.length() == 0) || (oldChars == null) || (oldChars.length == 0)) {
            return source;
        }
        StringBuilder sb = new StringBuilder(source.length());
        String toRv = String.valueOf(oldChars);
        for (int i = 0; i < source.length(); i++) {
            char c = source.charAt(i);
            if (toRv.indexOf(c) == -1) {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    public static String createXmlHeader(String docEncode) {
        StringBuilder header = new StringBuilder(46);
        header.append("<?xml version=\"1.0\" encoding=");
        if (docEncode == null) {
            docEncode = "GBK";
        }
        header.append("\"" + docEncode + "\"?>");

        return header.toString();
    }

    public static String fillCharAtFront(String toBeFilledStr, String fillChar, String totalLen) {
        int len = Integer.parseInt(totalLen);
        char ch = (fillChar != null) && (fillChar.length() > 0) ? fillChar.charAt(0) : ' ';
        return fillCharAtFront(toBeFilledStr, ch, len);
    }

    /**
     *
     * @param toBeFilledStr
     * @param fillChar
     * @param totalLen
     * @return
     */
    public static String fillCharAtFront(String toBeFilledStr, char fillChar, int totalLen) {
        if (toBeFilledStr == null) {
            toBeFilledStr = "";
        }
        byte[] b = toBeFilledStr.getBytes();
        int srcLen = b.length;
        if (srcLen >= totalLen) {
            return new String(b, 0, totalLen);
        }
        StringBuffer sb = new StringBuffer(totalLen);
        int count = totalLen - srcLen;
        char[] toAppend = new char[count];
        for (int i = 0; i < count; i++) {
            toAppend[i] = fillChar;
        }
        sb.append(toAppend);
        sb.append(toBeFilledStr);

        return sb.toString();
    }

    public static String fillCharAtBack(String toBeFilledStr, String fillChar, String totalLen) {
        int len = Integer.parseInt(totalLen);
        char ch = (fillChar != null) && (fillChar.length() > 0) ? fillChar.charAt(0) : ' ';
        return fillCharAtBack(toBeFilledStr, ch, len);
    }

    /**
     *
     * @param toBeFilledStr
     * @param fillChar
     * @param totalLen
     * @return
     */
    public static String fillCharAtBack(String toBeFilledStr, char fillChar, int totalLen) {
        if (toBeFilledStr == null) {
            toBeFilledStr = "";
        }
        byte[] b = toBeFilledStr.getBytes();
        int srcLen = b.length;
        if (srcLen >= totalLen) {
            return new String(b, 0, totalLen);
        }

        StringBuilder sb = new StringBuilder(totalLen);
        sb.append(toBeFilledStr);
        int count = totalLen - srcLen;
        char[] toAppend = new char[count];
        for (int i = 0; i < count; i++) {
            toAppend[i] = fillChar;
        }
        sb.append(toAppend);

        return sb.toString();
    }

    /**
     * @param c
     * @return
     */
    public static boolean isLetter(char c) {
        int k = 128;
        return c / k == 0;
    }

    public static String trim(String toTrim) {
        if ((toTrim == null) || (toTrim.length() == 0)) {
            return "";
        }
        return toTrim.trim();
    }

    public static String getXMLTextTrim(String text) {
        if (text == null) {
            return null;
        }
        return text;
    }

    /**
     *
     * @param source
     * @param ch
     * @return
     */
    public static Integer[] indexsOf(String source, char ch) {
        if (isBlank(source)) {
            return null;
        }

        List<Integer> list = null;
        int index = source.indexOf(ch);
        if (index >= 0) {
            list = new ArrayList<Integer>();
        }

        while (index >= 0) {
            list.add(Integer.valueOf(index));
            index = source.indexOf(ch, index + 1);
        }

        if ((list != null) && (list.size() > 0)) {
            Integer[] a = new Integer[list.size()];
            return (Integer[])list.toArray(a);
        }

        return null;
    }

    /**
     * 
     * @param source
     * @param fromIndex
     * @param str
     * @return
     */
    public static int indexOf(String source, int fromIndex, char[] str) {
        if (isBlank(source) || (str == null) || (str.length == 0)) {
            return -1;
        }

        int ret = -1;
        for (int i = fromIndex; i < source.length(); i++) {
            char ch = source.charAt(i);
            for (int j = 0; j < str.length; j++) {
                if (ch == str[j]) {
                    return i;
                }
            }
        }

        return ret;
    }

    /**
     *
     * @param source
     * @param str
     * @param beforeChar
     * @return
     */
    public static int indexOfExcludeBefore(String source, String str, char... beforeChar) {
        if (isBlank(source) || isBlank(str)) {
            return -1;
        }

        String exclude = beforeChar == null ? "" : String.copyValueOf(beforeChar);
        int index = source.indexOf(str);
        while (index >= 0) {
            if (index == 0) {
                return index;
            }

            int lastIndex = exclude.indexOf(source.charAt(index - 1));
            if (lastIndex < 0) {
                return index;
            }

            index = source.indexOf(str, index + str.length());
        }

        return -1;
    }

    public static int indexOfExcludeBefore(String source, int fromIndex, String str, char... beforeChar) {
        if (isBlank(source) || isBlank(str)) {
            return -1;
        }
        String exclude = beforeChar == null ? "" : String.copyValueOf(beforeChar);
        int index = source.indexOf(str, fromIndex);
        while (index >= 0) {
            if (exclude.indexOf(source.charAt(index - 1)) < 0) {
                return index;
            }
            index = source.indexOf(str, index + str.length());
        }

        return -1;
    }

    /**
     * 
     * @return
     */
    public static char getOSSeparator() {
        char[] separators = File.separator.toCharArray();
        char separator = separators[0];

        return separator;
    }

    /**
     * 
     * @param substVar
     * @return
     */
    public static String varname(String substVar) {
        if (isBlank(substVar)) {
            return "";
        }

        int i = 0, j;

        i = substVar.indexOf(DELIM_START, i);
        if (i == -1) {
            return "";
        } else {
            i += DELIM_START_LEN;
            j = substVar.indexOf(DELIM_STOP, i);
            if (j == -1) {
                throw new RuntimeException("Error in replacing string variables! No ending symbol");
            } else {
                String sv = substVar.substring(i, j);
                return sv;
            }
        }
    }

    public static boolean isNotBlank(final CharSequence cs) {
        return !isBlank(cs);
    }

    public static boolean isBlank(final CharSequence cs) {
        int strLen;
        if (cs == null || (strLen = cs.length()) == 0) {
            return true;
        }
        for (int i = 0; i < strLen; i++) {
            if (Character.isWhitespace(cs.charAt(i)) == false) {
                return false;
            }
        }
        return true;
    }

    public static String getSerialNo(int length) {
        long l = System.nanoTime();
        String str1 = (l / radix) + "";
        String str2 = (l & radix + 1) + "";

        ThreadLocalRandom r = ThreadLocalRandom.current();
        String str3 = r.nextInt(1000000000) + "";

        String str = str1.concat(str2).concat(str3);

        return fillLeftZero(str, length);
    }

    /**
     *
     * @param origStr
     * @param zeroStrLength
     * @return
     */
    public static final String fillLeftZero(String origStr, int zeroStrLength) {
        String zeroStr = "";
        StringBuffer buf = new StringBuffer();
        for (int i = 0; i < zeroStrLength; ++i) {
            buf.append("0");
        }
        zeroStr = buf.toString();

        StringBuilder sb = new StringBuilder(zeroStr);
        int zeroStrLen = zeroStr.length();
        int origStrLen = origStr.length();

        int oLen = origStr.length();
        if (oLen >= zeroStrLength) {
            return origStr.substring(oLen - zeroStrLength, oLen);
        }

        return sb.replace(zeroStrLen - origStrLen, zeroStrLen, origStr).toString();
    }

    /**
     *
     * @param origStr
     * @param length
     * @param fill
     * @param fillLength
     * @param mode
     * @return
     */
    public static final String fill(String origStr, int length, String fill, int fillLength, int mode) {
        if (origStr == null) {
            origStr = "";
        }

        if (length >= fillLength) {
            return origStr;
        }

        String fillStr = "";
        int origStrLen = origStr.length();
        if (origStrLen >= fillLength) {
            return origStr;
        }

        if (length > origStrLen) {
            fillLength = fillLength - length + origStrLen;
        }

        StringBuffer buf = new StringBuffer();
        for (int i = 0; i < fillLength; ++i) {
            buf.append(fill);
        }
        fillStr = buf.toString();
        if (origStrLen == 0) {
            return fillStr;
        }

        StringBuilder sb = new StringBuilder(fillStr);
        int fillStrLen = fillStr.length();

        if (1 == mode) {
            return sb.replace(fillStrLen - origStrLen, fillStrLen, origStr).toString();
        } else if (0 == mode) {
            return sb.replace(0, origStrLen, origStr).toString();
        }

        throw new RuntimeException("Unrecognized alignment method");
    }

    /**
     *
     * @param str
     * @param lastIndex
     * @return
     */
    public static String getSubStr(String str, String lastIndex) {
        int idx = str.lastIndexOf(lastIndex);
        String subStr = "";
        if (idx != -1) {
            subStr = str.substring(idx + 1, str.length());
        }

        return subStr;
    }
}